package com.ruoyi.cms.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.green20220302.Client;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.api.feign.ContentModerationService;
import com.ruoyi.cms.entity.domain.*;
import com.ruoyi.cms.entity.req.GenerateModelReq;
import com.ruoyi.cms.entity.req.ModelListReq;
import com.ruoyi.cms.entity.req.MoveToCollectionReq;
import com.ruoyi.cms.entity.req.ReGenerateModelReq;
import com.ruoyi.cms.entity.resp.FileListResp;
import com.ruoyi.cms.entity.resp.ModelAuthorInfo;
import com.ruoyi.cms.entity.resp.ModelDetailResp;
import com.ruoyi.cms.entity.resp.ModelListResp;
import com.ruoyi.cms.service.ModelIntroductionService;
import com.ruoyi.cms.service.ModelParameterService;
import com.ruoyi.common.enums.cms.*;
import com.ruoyi.api.entity.resp.MobileUserInfo;
import com.ruoyi.api.feign.MemberApiService;
import com.ruoyi.cms.mapper.*;
import com.ruoyi.common.context.AppUserContext;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.modules.CmsException;
import com.ruoyi.common.utils.oss.OssUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.ruoyi.cms.service.ModelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 模型Service业务层处理
 */
@Service
@Slf4j
public class ModelServiceImpl implements ModelService {

    @Autowired
    private ModelMapper modelMapper;
    @Autowired
    private ModelOriginalFileMapper modelOriginalFileMapper;
    @Autowired
    private ModelGenerateFileMapper modelGenerateFileFileMapper;
    @Autowired
    private UserMediaFileMapper userMediaFileMapper;
    @Autowired
    private ModelCollectionMapper modelCollectionMapper;
    @Autowired
    private MemberApiService memberApiService;
    @Autowired
    private ModelGenerateFileMapper modelGenerateFileMapper;
    @Autowired
    private ContentModerationService contentModerationService;
    @Autowired
    private ModelIntroductionService modelIntroductionService;
    @Autowired
    @Lazy
    private ModelParameterService modelParameterService;


    @Value(value = "${load-balancer.ip}")
    private List<String> balanceIp;

    @Override
    public R<Page<ModelListResp>> list(ModelListReq req) {
        Page<Model> page = new Page<>(req.getCurrent(), req.getSize());

        LambdaQueryWrapper<Model> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(req.getModelName()), Model::getName, req.getModelName());
        queryWrapper.eq(Model::getStatus, ModelStatusEnum.SUCCESS.getStatus());
        queryWrapper.eq(Model::getVisible, 2);
        queryWrapper.eq(null != req.getCollectionId(), Model::getCollectionId, req.getCollectionId());
        queryWrapper.eq(null != req.getUserId(), Model::getCreator, req.getUserId());
        queryWrapper.eq(Model::getDeleted, 0);

        if (Objects.equals(req.getTab(), 2)) {
            queryWrapper.orderByDesc(Model::getLikeNum);
        } else if (Objects.equals(req.getTab(), 3)) {
            queryWrapper.eq(Model::getFeatured, 1);
        }

        queryWrapper.orderByDesc(Model::getId);

        page = modelMapper.selectPage(page, queryWrapper);

        Page<ModelListResp> modelListRespPage = (Page<ModelListResp>) page.convert(model -> {
            ModelListResp modelListResp = new ModelListResp();
            ModelListResp.ModelDetail modelDetail = modelListResp.getModelDetail();

            modelDetail.setId(model.getId());
            modelDetail.setName(model.getName());
            modelDetail.setCoverPhotoUrl(model.getCoverPhotoUrl());
            modelDetail.setCreator(model.getCreator());
            modelDetail.setLikeNum(model.getLikeNum());
            modelDetail.setFavoriteNum(model.getFavoriteNum());
            modelDetail.setCreateTime(model.getCreateTime());

            modelListResp.setModelAuthorInfo(convertAuthorInfo(model.getCreator()));

            return modelListResp;
        });

        return R.ok(modelListRespPage);
    }

    public ModelAuthorInfo convertAuthorInfo(Long userId) {
        R<MobileUserInfo> resp = memberApiService.getInfo(userId);
        if (R.isError(resp) || resp.getData() == null) {
            return new ModelAuthorInfo();
        }

        MobileUserInfo info = resp.getData();

        ModelAuthorInfo modelAuthorInfo = new ModelAuthorInfo();
        modelAuthorInfo.setUserId(info.getId());
        modelAuthorInfo.setName(info.getName());
        modelAuthorInfo.setAvatar(info.getAvatar());
        modelAuthorInfo.setProfile(info.getProfile());
        return modelAuthorInfo;
    }

    @Override
    public R<Page<ModelListResp>> myModelList(ModelListReq req) {
        Page<Model> page = new Page<>(req.getCurrent(), req.getSize());

        LambdaQueryWrapper<Model> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(req.getModelName()), Model::getName, req.getModelName());
        queryWrapper.eq(Model::getCreator, AppUserContext.getUser().getUserId());
        queryWrapper.eq(null != req.getCollectionId(), Model::getCollectionId, req.getCollectionId());
        queryWrapper.eq(Model::getDeleted, 0);
        queryWrapper.orderByDesc(Model::getId);
        page = modelMapper.selectPage(page, queryWrapper);

        Page<ModelListResp> modelListRespPage = (Page<ModelListResp>) page.convert(model -> {
            ModelListResp modelListResp = new ModelListResp();
            ModelListResp.ModelDetail modelDetail = modelListResp.getModelDetail();

            modelDetail.setId(model.getId());
            modelDetail.setName(model.getName());
            modelDetail.setCoverPhotoUrl(model.getCoverPhotoUrl());
            modelDetail.setCreator(model.getCreator());
            modelDetail.setLikeNum(model.getLikeNum());
            modelDetail.setFavoriteNum(model.getFavoriteNum());
            modelDetail.setCreateTime(model.getCreateTime());
            modelDetail.setStatus(model.getStatus());

            modelListResp.setModelAuthorInfo(convertAuthorInfo(model.getCreator()));

            return modelListResp;
        });

        return R.ok(modelListRespPage);
    }

    @Override
    public R<FileListResp> getFileList(Long modelId) {
        FileListResp resp = new FileListResp();

        LambdaQueryWrapper<Model> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Model::getId, modelId);
        queryWrapper.eq(Model::getStatus, ModelStatusEnum.SUCCESS.getStatus());
        queryWrapper.eq(Model::getVisible, 2);
        queryWrapper.eq(Model::getDeleted, 0);
        queryWrapper.orderByDesc(Model::getId);
        queryWrapper.last("limit 1");
        Model model = modelMapper.selectOne(queryWrapper);
        if (null == model) {
            return R.fail("模型不存在");
        }

        resp.getModelDetail().setId(model.getId());
        resp.getModelDetail().setName(model.getName());
        resp.getModelDetail().setLikeNum(model.getLikeNum());
        resp.getModelDetail().setFavoriteNum(model.getFavoriteNum());
        resp.getModelDetail().setIntroduction(modelIntroductionService.getIntroduction(modelId));

        LambdaQueryWrapper<ModelGenerateFile> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(ModelGenerateFile::getModelId, modelId);
        List<ModelGenerateFile> modelGenerateFiles = modelGenerateFileFileMapper.selectList(queryWrapper2);

        resp.setFileList(modelGenerateFiles);

        resp.setModelAuthorInfo(convertAuthorInfo(model.getCreator()));

        resp.setModelParameter(modelParameterService.get(modelId));

        return R.ok(resp);
    }

    @Override
    public R<FileListResp> getMyFileList(Long modelId) {
        FileListResp resp = new FileListResp();

        LambdaQueryWrapper<Model> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Model::getId, modelId);
        //queryWrapper.eq(Model::getStatus, ModelStatusEnum.SUCCESS.getStatus());
        queryWrapper.eq(Model::getCreator, AppUserContext.getUser().getUserId());
        queryWrapper.eq(Model::getDeleted, 0);
        queryWrapper.orderByDesc(Model::getId);
        queryWrapper.last("limit 1");
        Model model = modelMapper.selectOne(queryWrapper);
        if (null == model) {
            return R.fail("模型不存在");
        }

        resp.getModelDetail().setId(model.getId());
        resp.getModelDetail().setName(model.getName());
        resp.getModelDetail().setLikeNum(model.getLikeNum());
        resp.getModelDetail().setFavoriteNum(model.getFavoriteNum());
        resp.getModelDetail().setIntroduction(modelIntroductionService.getIntroduction(modelId));

        LambdaQueryWrapper<ModelGenerateFile> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(ModelGenerateFile::getModelId, modelId);
        List<ModelGenerateFile> modelGenerateFiles = modelGenerateFileFileMapper.selectList(queryWrapper2);

        resp.setFileList(modelGenerateFiles);
        resp.setModelAuthorInfo(convertAuthorInfo(model.getCreator()));

        resp.setModelParameter(modelParameterService.get(modelId));

        return R.ok(resp);
    }

    @Override
    @Transactional
    public R<?> generate(GenerateModelReq req) {
        //审核标题
        Client client;
        try {
            client = contentModerationService.createSZClient();
        } catch (Exception e) {
            log.error("model generate moderation error", e);
            throw new CmsException("model generate moderation error");
        }
        if (!contentModerationService.textModeration(req.getName(), client)) {
            throw new CmsException(CmsErrorCode.TEXT_VIOLATION.getCode(), CmsErrorCode.TEXT_VIOLATION.getMsg());
        }

        Long userId = AppUserContext.getUser().getUserId();
        Date date = new Date();

        LambdaQueryWrapper<UserMediaFile> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(UserMediaFile::getId, req.getFileIds());
        queryWrapper.eq(UserMediaFile::getType, req.getOriginalType());
        queryWrapper.eq(UserMediaFile::getModerationStatus, FileModerationStatusEnum.PASS.getStatus());
        List<UserMediaFile> userMediaFiles = userMediaFileMapper.selectList(queryWrapper);

        if (CollUtil.isEmpty(userMediaFiles)) {
            return R.fail("请选择文件");
        }

        String coverPhotoUrl;
        if (OriginalFileType.IMAGES.getType().equals(req.getOriginalType())) {
            coverPhotoUrl = userMediaFiles.get(0).getUrl();
        } else {
            //视频暂时只处理一个文件
            userMediaFiles = userMediaFiles.subList(0, 1);
            coverPhotoUrl = userMediaFiles.get(0).getCoverPhotoUrl();
        }

        AtomicReference<Long> countSize = new AtomicReference<>(0L);
        userMediaFiles.forEach(file -> {
            countSize.updateAndGet(v -> v + file.getSize());
        });

        Model model = new Model();
        model.setName(req.getName());
        model.setSource(req.getSource());
        model.setOriginalType(req.getOriginalType());
        model.setStatus(ModelStatusEnum.QUEUING.getStatus());
        model.setCountSize(countSize.get());
        model.setCoverPhotoUrl(coverPhotoUrl);
        model.setCreator(userId);
        model.setUpdater(userId);
        model.setCreateTime(date);
        model.setUpdateTime(date);
        model.setServerIp(getIpBalance());

        modelMapper.insert(model);

        userMediaFiles.forEach(file -> {
            ModelOriginalFile modelOriginalFile = new ModelOriginalFile();
            modelOriginalFile.setModelId(model.getId());
            modelOriginalFile.setUrl(file.getUrl());
            modelOriginalFile.setObjectName(file.getObjectName());
            modelOriginalFile.setType(req.getOriginalType());
            modelOriginalFile.setCoverPhotoUrl(file.getCoverPhotoUrl());
            modelOriginalFile.setSize(file.getSize());
            modelOriginalFile.setCreator(userId);
            modelOriginalFile.setCreateTime(date);

            modelOriginalFileMapper.insert(modelOriginalFile);
        });

        //存简介
        new Thread(() -> modelIntroductionService.addIntroduction(model)).start();

        return R.ok();
    }

    //获取任务最少服务器的ip
    private String getIpBalance() {
        LambdaQueryWrapper<Model> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Model::getStatus, ModelStatusEnum.QUEUING.getStatus(), ModelStatusEnum.GENERATING.getStatus());
        queryWrapper.eq(Model::getDeleted, 0);

        List<Model> modelList = modelMapper.selectList(queryWrapper);

        if(CollUtil.isEmpty(modelList)){
            return balanceIp.get(0);
        }

        Map<String, Long> map = modelList.stream().collect(Collectors.groupingBy(Model::getServerIp, Collectors.counting()));

        Long min = Long.MAX_VALUE;
        String minIp = "";

        for (String ip : balanceIp) {
            if(map.containsKey(ip)) {
                if(map.get(ip) < min) {
                    min = map.get(ip);
                    minIp = ip;
                }
            } else {
                return ip;
            }
        }

        return minIp;
    }

    @Override
    public R<Page<ModelListResp>> queryModelByCollectionId(ModelListReq req) {
        if (null == req.getCollectionId()) {
            return R.fail("请选择合集");
        }
        return list(req);
    }

    @Override
    public R<Page<ModelListResp>> queryMyModelByCollectionId(ModelListReq req) {
        if (null == req.getCollectionId()) {
            return R.fail("请选择合集");
        }
        return myModelList(req);
    }

    @Override
    public R<?> delete(List<String> ids) {
        ids.forEach(id -> {
            Model model = modelMapper.selectById(id);
            modelCheck(model);

            modelMapper.deleteById(id);
        });
        return R.ok();
    }

    public void modelCheck(Model model) {
        if (ObjUtil.isNull(model) || model.getDeleted() == 1) {
            throw new CmsException("模型不存在");
        }
        if (model.getCreator().longValue() != AppUserContext.getUser().getUserId()) {
            throw new CmsException("您没有权限操作此模型");
        }
    }

    @Override
    public R<?> update(Model model) {
        //审核标题
        Client client;
        try {
            client = contentModerationService.createSZClient();
        } catch (Exception e) {
            log.error("model update moderation error", e);
            throw new CmsException("model update moderation error");
        }
        if (!contentModerationService.textModeration(model.getName(), client)) {
            throw new CmsException(CmsErrorCode.TEXT_VIOLATION.getCode(), CmsErrorCode.TEXT_VIOLATION.getMsg());
        }

        Model model2 = modelMapper.selectById(model.getId());
        modelCheck(model2);

        if (null != model.getCollectionId()) {
            ModelCollection modelCollection = modelCollectionMapper.selectById(model.getCollectionId());
            collectionCheck(modelCollection);
        }

        boolean updateName = StrUtil.isNotBlank(model.getName()) && !model.getName().equals(model2.getName());

        model2.setName(model.getName());
        model2.setCollectionId(model.getCollectionId());
        model2.setVisible(model.getVisible());
        model2.setUpdater(AppUserContext.getUser().getUserId());
        model2.setUpdateTime(new Date());
        modelMapper.updateById(model2);

        //存简介
        if(updateName) {
            new Thread(() -> modelIntroductionService.updateIntroduction(model2)).start();
        }

        return R.ok();
    }

    public void collectionCheck(ModelCollection modelCollection) {
        if (ObjUtil.isNull(modelCollection) || modelCollection.getDeleted() == 1) {
            throw new CmsException("合集不存在");
        }
        if (modelCollection.getCreator().longValue() != AppUserContext.getUser().getUserId()) {
            throw new CmsException("您没有权限操作此合集");
        }
    }

    @Override
    public R<ModelDetailResp> detail(Long id) {
        Model model = modelMapper.selectById(id);

        ModelDetailResp resp = convert(model);
        return R.ok(resp);
    }

    private ModelDetailResp convert(Model model) {
        ModelDetailResp resp = new ModelDetailResp();

        ModelDetailResp.ModelDetail modelDetail = resp.getModelDetail();

        modelDetail.setSource(model.getSource());
        modelDetail.setOriginalNum(model.getOriginalNum());
        modelDetail.setOriginalType(model.getOriginalType());
        modelDetail.setCreateTime(model.getCreateTime());
        modelDetail.setCoverPhotoUrl(model.getCoverPhotoUrl());

        //模型大小
        LambdaQueryWrapper<ModelGenerateFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ModelGenerateFile::getModelId, model.getId());
        List<ModelGenerateFile> modelGenerateFiles = modelGenerateFileMapper.selectList(wrapper);

        for (ModelGenerateFile modelGenerateFile : modelGenerateFiles) {
            if (Objects.equals(modelGenerateFile.getType(), GenerateFileType.SPLAT_7000.getType())) {
                modelDetail.setAppModelSize(modelGenerateFile.getSize());
            } else if (Objects.equals(modelGenerateFile.getType(), GenerateFileType.SPLAT_30000.getType())) {
                modelDetail.setPcModelSize(modelGenerateFile.getSize());
            }
        }


        resp.setModelAuthorInfo(convertAuthorInfo(model.getCreator()));

        return resp;
    }

    @Override
    public R<ModelDetailResp> myDetail(Long id) {
        Model model = modelMapper.selectById(id);
        modelCheck(model);

        ModelDetailResp resp = convert(model);
        return R.ok(resp);
    }

    @Override
    public R<?> moveToCollection(MoveToCollectionReq req) {
        CollUtil.emptyIfNull(req.getModelIds()).forEach(e -> {
            Model model = modelMapper.selectById(e);
            modelCheck(model);

            model.setCollectionId(Long.valueOf(req.getCollectionId()));
            modelMapper.updateById(model);
        });

        return R.ok();
    }

    @Override
    @Transactional
    public R<?> reGenerate(ReGenerateModelReq req) throws Exception {
        //删除生成表
        LambdaQueryWrapper<ModelGenerateFile> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ModelGenerateFile::getModelId, req.getModelId());
        List<ModelGenerateFile> modelGenerateFiles = modelGenerateFileMapper.selectList(wrapper);

        List<String> keys = modelGenerateFiles.stream().map(ModelGenerateFile::getObjectName).collect(Collectors.toList());
        OssUtil.deleteObjects(keys);

        modelGenerateFiles.forEach(e -> modelGenerateFileMapper.deleteById(e));

        //重新排队
        Model model = modelMapper.selectById(req.getModelId());
        model.setStatus(ModelStatusEnum.QUEUING.getStatus());
        model.setFrameInterval(req.getFrameInterval());
        model.setUpdateTime(new Date());
        modelMapper.updateById(model);

        return R.ok();
    }


}
